using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Transactions;
using Elsa.Services.Models;
using HengTong.Model._Admin;
using HengTong.Model.Db;
using HengTong.Model.Db.Hr;
using HengTong.Model.Db.Hr.Bill;
using HengTong.Model.Db.System;
using HengTong.Model.Services;
using HengTong.ViewModel._Admin.SysUserJobPositionVms;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using TiaoTaoHelper.Extension.Object;
using TiaoTaoHelper.Models;
using TiaoTaoHelper.Wtm.Interfaces;
using TiaoTaoHelper.Wtm.Models;
using TiaoTaoHelper.Wtm.Workflow;
using UUIDNext;
using WalkingTec.Mvvm.Core;
using WalkingTec.Mvvm.Core.Support.Json;
using WalkingTec.Mvvm.Core.WorkFlow;

namespace HengTong.ViewModel.Person.SysPersonRepairBillVms;

public partial class SysPersonRepairBillVm
{
    private ILogger<SysPersonRepairBillVm> _logger;

    public override async Task DoAddAsync()
    {
        // 判断当前用户是否已经有正在流程中的数据
        var existingBill = await DC.Set<SysPersonRepairBill>()
            .Where(x => x.StaffNo == Entity.StaffNo
                        && (x.WorkflowStatus == WorkflowStatus.待提交
                            || x.WorkflowStatus == WorkflowStatus.审核中
                            || x.WorkflowStatus == WorkflowStatus.提交中))
            .AsNoTracking()
            .FirstOrDefaultAsync();

        if (existingBill != null)
        {
            MSD.AddModelError(" ", "您已有正在流程中的单据，请等待审核完成后再提交新的单据。");
            return;
        }

        Entity.ID = Uuid.NewDatabaseFriendly(Database.SqlServer);

        if (Entity is IBill bill)
        {
            Entity.BillStatus ??= BillStatus.草稿;
            Entity.WorkflowStatus = WorkflowStatus.待提交;
            var result = await GenerateCodeAsync();
            if (result.Code == 200)
            {
                Entity.BillCode = result.Data;
            }
            else
            {
                MSD.AddModelError(" ", $"生成编码异常. {result.Message}");
                return;
            }
        }

        if (Entity is IBasePoco poco)
        {
            poco.CreateBy = Entity.StaffNo;
            poco.UpdateBy = Wtm.LoginUserInfo?.ITCode;
            poco.CreateTime = DateTime.Now;
            poco.UpdateTime = DateTime.Now;
        }

        await base.DoAddAsync();
    }

    /// <summary>
    /// 生成编码
    /// </summary>
    /// <returns></returns>
    public async Task<Result<string>> GenerateCodeAsync()
    {
        if (Entity is IBill bill)
        {
            var scope = Wtm.ServiceProvider.CreateScope();
            var service = scope.ServiceProvider.GetRequiredService<CodeGeneratorService>();
            var code = await service.GenerateCodeAsync(Entity.GetType().Name);
            return new Result<string>()
            {
                Data = code
            };
        }

        return new Result<string>("实体未实现IBill接口");
    }

    /// <summary>
    /// 预测编码
    /// </summary>
    /// <returns></returns>
    public async Task<Result<string>> PredictCodeAsync()
    {
        if (Entity is IBill bill)
        {
            var scope = Wtm.ServiceProvider.CreateScope();
            var service = scope.ServiceProvider.GetRequiredService<CodeGeneratorService>();
            var code = await service.PreviewNextCodeAsync(Entity.GetType().Name);
            return new Result<string>()
            {
                Data = code
            };
        }

        return new Result<string>("实体未实现IBill接口");
    }

    public override async Task DoEditAsync(bool updateAllFields = false)
    {
        // 是否退伍军人校验
        if (Entity.IsVeteran == true && Entity.VeteranCertificateId == null)
        {
            MSD.AddModelError(" ", "请上传退伍证书");
            return;
        }

        // 判断手机号是否在 FrameworkUser 已经存在
        var existingUser = await DC.Set<FrameworkUser>()
            .AsNoTracking()
            .FirstOrDefaultAsync(u =>
                u.CellPhone == Entity.Phone && u.ITCode != Entity.StaffNo);
        if (existingUser != null)
        {
            MSD.AddModelError(" ", "手机号已被其他用户使用，请更换手机号。");
            return;
        }

        // 判断手机号是否在 SysPerson 已经存在
        var existingPerson = await DC.Set<SysPerson>()
            .AsNoTracking()
            .FirstOrDefaultAsync(p =>
                p.Phone == Entity.Phone && p.StaffNo != Entity.StaffNo && p.GetType() == typeof(SysPerson));
        if (existingPerson != null)
        {
            MSD.AddModelError(" ", "手机号已被其他人员档案使用，请更换手机号。");
            return;
        }

        if (Entity is IBill { WorkflowStatus: WorkflowStatus.提交中 })
        {
            // 判断子表家庭成员是否有数据，如果没有不发保存
            var families = await DC.Set<SysPersonFamily>()
                .Where(f => f.PersonId == Entity.ID)
                .AsNoTracking()
                .ToListAsync();
            if (!families.Any())
            {
                MSD.AddModelError(" ", "请至少添加一条家庭成员信息");
                return;
            }

            var raw = await DC.Set<SysPersonRepairBill>()
                .AsNoTracking()
                .FirstOrDefaultAsync(e => e.ID == Entity.ID);
            if (raw.WorkflowStatus != WorkflowStatus.待提交)
            {
                MSD.AddModelError(" ", "单据已提交审核,请勿重复提交.");
                return;
            }

            //判断人员是否设定部门
            if (Wtm.LoginUserInfo?.Groups?.Count == 0)
            {
                var group = await DC.Set<SysGroup>()
                    .AsNoTracking()
                    .Where(e => e.ID == Entity.GroupId)
                    .FirstOrDefaultAsync();
                if (group != null)
                {
                    var d = new FrameworkUserGroup
                    {
                        GroupCode = group.GroupCode,
                        TenantCode = Wtm.LoginUserInfo.CurrentTenant,
                        UserCode = Wtm.LoginUserInfo?.ITCode
                    };
                    await DC.Set<FrameworkUserGroup>().AddAsync(d);
                    await DC.SaveChangesAsync();
                    Wtm.LoginUserInfo?.Groups.Add(new SimpleGroup()
                    {
                        ID = group.ID,
                        GroupCode = group.GroupCode,
                        GroupName = group.GroupName
                    });
                    await Wtm.RemoveUserCache([d.UserCode]);
                }
            }

            var result = await StartWorkflowAsync("档案补录流程");
            if (result == null) return;
            if (!result.Executed)
            {
                MSD.AddModelError(" ", $"提交审核异常. {result.Exception?.Message}");
                return;
            }

            Entity.BillStatus = BillStatus.正文;
            Entity.WorkflowStatus = WorkflowStatus.审核中;
        }

        if (Entity is IBasePoco poco)
        {
            poco.UpdateBy = Wtm.LoginUserInfo?.ITCode;
            poco.UpdateTime = DateTime.Now;
        }

        await base.DoEditAsync(updateAllFields);
    }


    [WorkflowOperation("取消", "将流程状态设置为取消", "信息补录")]
    public async Task Cancel(ActivityExecutionContext context)
    {
        if (Entity is IBasePoco poco)
        {
            poco.UpdateTime = DateTime.Now;
            DC.UpdateProperty(Entity, x => x.UpdateTime);
            if (context.Input is WtmApproveInput input)
            {
                poco.UpdateBy = input.CurrentUser?.ITCode ?? "workflow";
                DC.UpdateProperty(Entity, x => x.UpdateBy);
            }
        }

        if (Entity is IBill bill)
        {
            bill.WorkflowStatus = WorkflowStatus.已取消;
            DC.UpdateProperty(Entity, x => x.WorkflowStatus);
        }

        await DC.SaveChangesAsync();
    }

    [WorkflowOperation("驳回", "将单据状态设置为草稿", "信息补录")]
    public async Task Reject(ActivityExecutionContext context)
    {
        Entity.BillStatus = BillStatus.草稿;
        if (Entity is IBasePoco poco)
        {
            poco.UpdateTime = DateTime.Now;
            DC.UpdateProperty(Entity, x => x.UpdateTime);
            if (context.Input is WtmApproveInput input)
            {
                poco.UpdateBy = input.CurrentUser?.ITCode ?? "workflow";
                DC.UpdateProperty(Entity, x => x.UpdateBy);
            }
        }

        DC.UpdateProperty(Entity, x => x.BillStatus);
        await DC.SaveChangesAsync();
    }


    /// <summary>
    /// 补录流程结束后，将补录数据更新到人员档案：学习经历，家庭成员，工作经历，员工履历，荣誉职称
    /// </summary>
    [WorkflowOperation("更新档案", "将补录单据数据更新到人员档案", "信息补录")]
    public async Task UpdatePersonArchive(ActivityExecutionContext context)
    {
        string currentUser = "workflow";
        if (context.Input is WtmApproveInput input)
        {
            currentUser = input.CurrentUser?.ITCode ?? "workflow";
        }

        if (Entity == null || Entity.ID == Guid.Empty)
        {
            MSD.AddModelError(" ", "补录单据不存在");
            return;
        }

        await UpdatePersonArchiveCore(Entity.ID, Entity.StaffNo, currentUser);
    }


    /// <summary>
    /// 通用档案更新核心方法，供补录和update复用
    /// </summary>
    private async Task UpdatePersonArchiveCore(Guid sourceBillId, string staffNo, string currentUser)
    {
        // 在方法开始处获取 logger
        var scope = Wtm.ServiceProvider.CreateScope();
        _logger = scope.ServiceProvider.GetRequiredService<ILogger<SysPersonRepairBillVm>>();

        using var transactionScope = new TransactionScope(
            TransactionScopeOption.Required,
            new TransactionOptions
            {
                IsolationLevel = IsolationLevel.ReadCommitted,
                Timeout = TimeSpan.FromMinutes(10)
            },
            TransactionScopeAsyncFlowOption.Enabled);

        try
        {
            _logger.LogInformation("开始更新人员档案，单据ID: {SourceBillId}, 工号: {StaffNo}, 操作人: {CurrentUser}, 时间: {Time}",
                sourceBillId, staffNo, currentUser, DateTime.Now);

            var targetPerson = await DC.Set<SysPerson>()
                .Where(x => x.GetType() == typeof(SysPerson))
                .AsNoTracking()
                .FirstOrDefaultAsync(p => p.StaffNo == staffNo);
            if (targetPerson == null)
            {
                _logger.LogWarning("未找到工号为 {StaffNo} 的人员档案，单据ID: {SourceBillId}", staffNo, sourceBillId);
                throw new Exception($"未找到工号为 {staffNo} 的人员档案");
            }

            var targetPersonId = targetPerson.ID;
            var currentTime = DateTime.Now;

            // 清除附件
            Entity.IdCardBackPhoto = null;
            Entity.IdCardFrontPhoto = null;
            Entity.Photo = null;
            Entity.Resume = null;
            //targetPerson.Order为null赋值为99
            Entity.Order = targetPerson.Order ?? 99;

            Entity.CloneMatchingProperties(targetPerson);
            targetPerson.ID = targetPersonId;
            targetPerson.UpdateTime = currentTime;
            targetPerson.UpdateBy = Entity.StaffNo;

            _logger.LogInformation("清除原有子表数据，人员ID: {PersonId}", targetPersonId);

            // 先删除学历附件表
            var existingEducationIds = await DC.Set<SysPersonEducation>()
                .Where(e => e.PersonId == targetPersonId)
                .Select(e => e.ID)
                .ToListAsync();

            if (existingEducationIds.Any())
            {
                await DC.Set<SysPersonEducationFile>()
                    .Where(f => existingEducationIds.Contains((Guid)f.PersonEducationId))
                    .ExecuteDeleteAsync();
            }

            // 删除子表数据
            await DC.Set<SysPersonEducation>().Where(e => e.PersonId == targetPersonId).ExecuteDeleteAsync();
            await DC.Set<SysPersonFamily>().Where(f => f.PersonId == targetPersonId).ExecuteDeleteAsync();
            await DC.Set<SysPersonWork>().Where(w => w.PersonId == targetPersonId).ExecuteDeleteAsync();
            await DC.Set<SysPersonResume>().Where(w => w.PersonId == targetPersonId).ExecuteDeleteAsync();
            await DC.Set<SysPersonProfessionalTitle>().Where(h => h.PersonId == targetPersonId).ExecuteDeleteAsync();

            await CopyEducationWithAttachments(sourceBillId, targetPersonId, currentTime, currentUser);
            //await CopyRepairDataToArchiveOptimized<SysPersonEducation>(sourceBillId, targetPersonId, currentTime,currentUser);
            await CopyRepairDataToArchiveOptimized<SysPersonFamily>(sourceBillId, targetPersonId, currentTime,
                currentUser);
            await CopyRepairDataToArchiveOptimized<SysPersonWork>(sourceBillId, targetPersonId, currentTime,
                currentUser);
            await CopyRepairDataToArchiveOptimized<SysPersonResume>(sourceBillId, targetPersonId, currentTime,
                currentUser);
            await CopyRepairDataToArchiveOptimized<SysPersonProfessionalTitle>(sourceBillId, targetPersonId,
                currentTime, currentUser);

            DC.Set<SysPerson>().Update(targetPerson);

            // 更新单据状态
            Entity.WorkflowStatus = WorkflowStatus.已完成;
            DC.UpdateProperty(Entity, x => x.WorkflowStatus);
            _logger.LogInformation("更新主表和子表数据完成，准备提交数据库，人员ID: {PersonId}", targetPersonId);
            await DC.SaveChangesAsync();

            // 更新FrameworkUser表的图片，手机号，名字
            if (Entity.PhotoId != null && Entity.Phone != null && Entity.Name != null)
            {
                await DC.Set<FrameworkUser>().Where(va => va.ITCode == Entity.StaffNo)
                    .ExecuteUpdateAsync(u => u
                        .SetProperty(x => x.PhotoId, Entity.PhotoId)
                        .SetProperty(x => x.CellPhone, Entity.Phone)
                        .SetProperty(x => x.Name, Entity.Name)
                    );
                await DC.SaveChangesAsync();
                await Wtm.RemoveUserCache(Entity.StaffNo);
            }

            // 更新岗位
            if (Entity.JobPositionId != null)
            {
                // 查询当前人员档案的工号的userid
                var targetUser = await DC.Set<FrameworkUser>()
                    .AsNoTracking()
                    .FirstOrDefaultAsync(u => u.ITCode == Entity.StaffNo);

                if (targetUser != null)
                {
                    /*// 先删除原有的岗位信息
                    await DC.Set<SysUserJobPosition>()
                        .Where(e => e.UserId == targetUser.ID)
                        .ExecuteDeleteAsync();*/

                    // 先判断是否已存在相同的岗位
                    var existingJobPosition = await DC.Set<SysUserJobPosition>()
                        .Where(e => e.UserId == targetUser.ID && e.JobPositionId == Entity.JobPositionId)
                        .AsNoTracking()
                        .FirstOrDefaultAsync();

                    // 如果不存在相同岗位，才添加新岗位
                    if (existingJobPosition == null)
                    {
                        // 添加新的岗位信息
                        var newJobPosition = new SysUserJobPosition
                        {
                            UserId = targetUser.ID,
                            JobPositionId = Entity.JobPositionId.Value
                        };
                        await DC.Set<SysUserJobPosition>().AddAsync(newJobPosition);
                        await DC.SaveChangesAsync();

                        var jobPositionVm = new SysUserJobPositionVm
                        {
                            DC = this.DC,
                            Wtm = this.Wtm
                        };
                        await jobPositionVm.UpdateUserGroupAsync(targetUser.ID);
                        await Wtm.RemoveUserCache(Entity.StaffNo);
                    }
                }
            }

            await DC.SaveChangesAsync();
            transactionScope.Complete();
            _logger.LogInformation("成功更新人员档案，StaffNo: {StaffNo}", Entity.StaffNo);
            _logger.LogInformation("流程状态，WorkflowStatus: {WorkflowStatus}", Entity.WorkflowStatus);
        }
        catch (Exception e)
        {
            _logger.LogError(e, "更新人员档案失败，单据ID: {SourceBillId}, 工号: {StaffNo}, 操作人: {CurrentUser}, 时间: {Time}",
                sourceBillId, staffNo, currentUser, DateTime.Now);
            MSD.AddModelError(" ", $"更新人员档案失败: {e.Message}");
        }
    }

    /// <summary>
    /// 优化的补录数据复制方法
    /// </summary>
    private async Task CopyRepairDataToArchiveOptimized<T>(Guid repairBillId, Guid targetPersonId, DateTime currentTime,
        string currentUser)
        where T : class, new()
    {
        var repairData = await DC.Set<T>()
            .Where(e => EF.Property<Guid>(e, "PersonId") == repairBillId)
            .AsNoTracking()
            .ToListAsync();

        if (!repairData.Any()) return;

        var newEntities = new List<T>();

        foreach (var item in repairData)
        {
            var newItem = new T();
            item.CloneMatchingProperties(newItem);

            if (newItem is IBasePoco poco)
            {
                poco.CreateTime = currentTime;
                poco.UpdateTime = currentTime;
                poco.CreateBy = currentUser;
                poco.UpdateBy = currentUser;
            }

            typeof(T).GetProperty("ID")?.SetValue(newItem, Uuid.NewDatabaseFriendly(Database.SqlServer));
            typeof(T).GetProperty("PersonId")?.SetValue(newItem, targetPersonId);

            newEntities.Add(newItem);
        }

        if (newEntities.Any())
        {
            await DC.Set<T>().AddRangeAsync(newEntities);
        }
    }

    /// <summary>
    /// 复制学历数据及其附件到目标档案
    /// </summary>
    private async Task CopyEducationWithAttachments(Guid repairBillId, Guid targetPersonId, DateTime currentTime,
        string currentUser)
    {
        var repairEducations = await DC.Set<SysPersonEducation>()
            .Where(e => e.PersonId == repairBillId)
            .Include(e => e.Attachments)
            .AsNoTracking()
            .ToListAsync();

        if (!repairEducations.Any()) return;

        var newEducations = new List<SysPersonEducation>();

        foreach (var item in repairEducations)
        {
            var newEducation = new SysPersonEducation();
            item.CloneMatchingProperties(newEducation);

            if (newEducation is IBasePoco poco)
            {
                poco.CreateTime = currentTime;
                poco.UpdateTime = currentTime;
                poco.CreateBy = currentUser;
                poco.UpdateBy = currentUser;
            }

            var newEducationId = Uuid.NewDatabaseFriendly(Database.SqlServer);
            newEducation.ID = newEducationId;
            newEducation.PersonId = targetPersonId;

            // 复制附件信息
            if (item.Attachments?.Any() == true)
            {
                newEducation.Attachments = item.Attachments.Select(att =>
                {
                    var newAttachment = new SysPersonEducationFile();
                    att.CloneMatchingProperties(newAttachment);
                    newAttachment.ID = Uuid.NewDatabaseFriendly(Database.SqlServer);
                    newAttachment.PersonEducationId = newEducationId;
                    return newAttachment;
                }).ToList();
            }

            newEducations.Add(newEducation);
        }

        if (newEducations.Any())
        {
            await DC.Set<SysPersonEducation>().AddRangeAsync(newEducations);
        }
    }
}